﻿using Masuit.Tools.DateTimeExt;
using Masuit.Tools.Strings;
using System;
using System.Linq;
using System.Net.NetworkInformation;
using Masuit.Tools.Hardware;
using System.Collections.Generic;
using System.Net.Sockets;

namespace Masuit.Tools.Systems
{
	/// <summary>
	/// 动态生产有规律的分布式ID
	/// </summary>
	public class SnowFlake
	{
		#region 私有字段

		private static long _offset; //起始偏移量
		private static long _machineId; //机器码
		private static long _sequence; //计数从零开始
		private static long _lastTimestamp = -1L; //最后时间戳

		private const long Twepoch = 687888001020L; //唯一时间随机量

		private const int MachineBits = 10; //机器码字节数

		private const int SequenceBits = 12; //计数器字节数，12个字节用来保存计数码
		private const int MachineLeft = SequenceBits; //机器码数据左移位数，就是后面计数器占用的位数
		private const long TimestampLeft = MachineBits + SequenceBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
		private const long SequenceMask = -1L ^ -1L << SequenceBits; //一毫秒内可以产生计数，如果达到该值则等到下一毫秒在进行生成

		private static readonly object SyncRoot = new(); //加锁对象
		private static NumberFormater _numberFormater = new(36);
		private static SnowFlake _snowFlake;

		#endregion 私有字段

		/// <summary>
		/// 获取一个新的id
		/// </summary>
		public static string NewId => GetInstance().GetUniqueId();

		/// <summary>
		/// 获取一个新的id
		/// </summary>
		public static long LongId => GetInstance().GetLongId();

		/// <summary>
		/// 创建一个实例
		/// </summary>
		/// <returns></returns>
		public static SnowFlake GetInstance()
		{
			return _snowFlake ??= new SnowFlake();
		}

		/// <summary>
		/// 默认构造函数
		/// </summary>
		public SnowFlake()
		{
		}

		/// <summary>
		/// 默认构造函数
		/// </summary>
		static SnowFlake()
		{
			try
			{
				var mac = SystemInfo.GetMacAddress().FirstOrDefault(a => a.GetAddressBytes().Length > 0);
				if (mac != null)
				{
					var bytes = mac.GetAddressBytes();
					SetMachienId(bytes[4] << 2 | bytes[5]);
				}
				else
				{
					var ip = SystemInfo.GetLocalUsedIP();
					if (ip != null)
					{
						var bytes = ip.GetAddressBytes();
						SetMachienId(bytes[3]);
					}
				}
			}
			catch
			{
				SetMachienId(0);
			}
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="machineId">机器码</param>
		public SnowFlake(long machineId)
		{
			SetMachienId(machineId);
		}

		public static void SetMachienId(long machineId)
		{
			if (machineId >= 0)
			{
				if (machineId > 1024)
				{
					throw new Exception("机器码ID非法");
				}

				_machineId = machineId;
			}
		}

		/// <summary>
		/// 设置数制格式化器
		/// </summary>
		/// <param name="nf"></param>
		public static void SetNumberFormater(NumberFormater nf)
		{
			_numberFormater = nf;
		}

		/// <summary>
		/// 设置起始偏移量
		/// </summary>
		/// <param name="offset"></param>
		public static void SetInitialOffset(long offset)
		{
			_offset = offset;
		}

		/// <summary>
		/// 获取长整形的ID
		/// </summary>
		/// <returns></returns>
		public long GetLongId()
		{
			lock (SyncRoot)
			{
				var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
				if (_lastTimestamp == timestamp)
				{
					//同一毫秒中生成ID
					_sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
					if (_sequence == 0)
					{
						//一毫秒内产生的ID计数已达上限，等待下一毫秒
						timestamp = DateTime.UtcNow.GetTotalMilliseconds();
					}
				}
				else
				{
					//不同毫秒生成ID
					_sequence = 0L;
				}

				_lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
				long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
				return id - _offset;
			}
		}

		/// <summary>
		/// 获取一个字符串表示形式的id
		/// </summary>
		/// <returns></returns>
		public string GetUniqueId()
		{
			return _numberFormater.ToString(GetLongId());
		}

		/// <summary>
		/// 获取一个字符串表示形式的id
		/// </summary>
		/// <param name="maxLength">最大长度，至少6位</param>
		/// <returns></returns>
		public string GetUniqueShortId(int maxLength = 8)
		{
			if (maxLength < 6)
			{
				throw new ArgumentException("最大长度至少需要6位");
			}

			string id = GetUniqueId();
			int index = id.Length - maxLength;
			if (index < 0)
			{
				index = 0;
			}

			return id.Substring(index);
		}
	}
}